package com.lijunjie.platform.api.aop;

import com.alibaba.fastjson.JSON;
import com.lijunjie.platform.api.modules.sys.entity.ExceptionLog;
import com.lijunjie.platform.api.modules.sys.entity.OperationLog;
import com.lijunjie.platform.api.modules.sys.entity.User;
import com.lijunjie.platform.api.modules.sys.service.IExceptionLogService;
import com.lijunjie.platform.api.modules.sys.service.IOperationLogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.UUID;

@Aspect
@Component
@Slf4j
@Order(-1)
public class MyAspect {

    ThreadLocal<Long> startTime = new ThreadLocal<>();

    @Resource
    private IOperationLogService operationLogService;

    @Resource
    private IExceptionLogService exceptionLogService;

    @Pointcut("execution(public * com.lijunjie.platform.api.modules.*.controller.*.*(..))")
    public void pointcut() {
    }

    @Before(value = "pointcut()")
    public void doBefore() {
        startTime.set(System.currentTimeMillis());
    }

    /**
     * 正确执行完后调用方法
     *
     * @param joinPoint 连接点
     * @param result    方法执行完的返回值
     */
    @AfterReturning(value = "pointcut()", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object result) {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        User operateUser = (User) SecurityUtils.getSubject().getPrincipal();

        OperationLog operationLog = new OperationLog();
        operationLog.setId(UUID.randomUUID().toString());
        operationLog.setOperateTime(LocalDateTime.now());
        operationLog.setOperateUserId(operateUser.getId());
        operationLog.setOperateUserName(operateUser.getUsername());
        operationLog.setRequestIp(request.getRemoteAddr());
        operationLog.setRequestUri(request.getRequestURI());
        operationLog.setRequestMethod(request.getMethod());
        operationLog.setRequestClassName(joinPoint.getTarget().getClass().getName());
        operationLog.setRequestClassMethod(joinPoint.getSignature().getName());
        operationLog.setRequestParameter(JSON.toJSON(request.getParameterMap()).toString());
        operationLog.setRequestResult(JSON.toJSON(result).toString());
        operationLog.setExecutionTime((int) (System.currentTimeMillis() - startTime.get()));
        operationLogService.save(operationLog);

    }

    /**
     * 有异常抛出之后执行该方法
     *
     * @param joinPoint 连接点
     * @param ex        异常
     */
    @AfterThrowing(value = "pointcut()", throwing = "ex")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable ex) {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        User operateUser = (User) SecurityUtils.getSubject().getPrincipal();

        ExceptionLog exceptionLog = new ExceptionLog();
        exceptionLog.setId(UUID.randomUUID().toString());
        exceptionLog.setOperateTime(LocalDateTime.now());
        if (operateUser != null) {
            exceptionLog.setOperateUserId(operateUser.getId());
            exceptionLog.setOperateUserName(operateUser.getUsername());
        }
        exceptionLog.setRequestIp(request.getRemoteAddr());
        exceptionLog.setRequestUri(request.getRequestURI());
        exceptionLog.setRequestMethod(request.getMethod());
        exceptionLog.setRequestClassName(joinPoint.getTarget().getClass().getName());
        exceptionLog.setRequestClassMethod(joinPoint.getSignature().getName());
        exceptionLog.setRequestParameter(JSON.toJSON(request.getParameterMap()).toString());
        exceptionLog.setExceptionMsg(ex.getMessage());
        exceptionLog.setExecutionTime((int) (System.currentTimeMillis() - startTime.get()));

        exceptionLogService.save(exceptionLog);

    }

}
